<?php
/***************************************************************************
 * 
 * Copyright (c) 2010 , Inc. All Rights Reserved
 * $Id$:hapn.php,2010/05/07 13:57:27 
 * 
 **************************************************************************/
 
 
 
/**
 * @file WebApp.php
 * @author huqingping
 * @date 2010/05/07 13:57:27
 * @version 1.0 
 * @brief 
 *  
 **/

final class WebApp extends BaseApp
{
	public $filterExecutor = null;
	public $request = null;
	public $response = null;
	// 是否为后台运行的模式
	// 如果处于这种模式，会先调用fastcgi_finish_request直接返回，然后再执行相关内容，这种模式下不会有response过程，否则会引起失败
	// modified by ronnie 2014/03/05
	public $isTask = false;

	function __construct()
	{
		parent::__construct();
		$this->mode = 'web';
	}

	function process()
	{
		if (false === $this->filterExecutor->executeFilter('init')) {
			return;
		}

		if (false === $this->filterExecutor->executeFilter('input')) {
			return;
		}
		if (false === $this->filterExecutor->executeFilter('url')) {
			return;
		}
		// 非后台任务才有输出
		if (!$this->isTask && false === $this->filterExecutor->executeFilter('output')) {
			return;
		}
	}

	function genAppId()
	{
		if (isset($_SERVER['HTTP_CLIENTAPPID'])) {
			return intval($_SERVER['HTTP_CLIENTAPPID']);
		}
		$reqip = '127.0.0.1';
		if (isset($_SERVER['HTTP_CLIENTIP'])) {
			$reqip = $_SERVER['HTTP_CLIENTIP'];
		}elseif (isset($_SERVER['REMOTE_ADDR'])) {
			$reqip = $_SERVER['REMOTE_ADDR'];
		}
		$time = gettimeofday(); 
		$time = $time['sec'] * 100 + $time['usec'];
		$ip = ip2long($reqip);
		$id = ($time ^ $ip)  & 0xFFFFFFFF;
		return floor($id/100)*100;
	}
	
	function run()
	{
		if ($this->isTask) {
			// 后台任务允许执行10分钟的时间
			ini_set('max_execution_time', 10*60);
			fastcgi_finish_request();
			// 后续要求不再有任何输出
			
			//加载Cache模块
			require_once LIB_ROOT.'com/Com.php';
			$conf = Conf::get('hapn.com');
			if ($this->debug) {
				$conf['log_func'] = 'Logger::debug';
			}
			Com::init($conf);
		}
		parent::run();
	}
	
	function init()
	{
		$this->_initWebObject();
		parent::init();
		$this->_initFilter();
	}

	private function _initWebObject()
	{
		require_once FR_ROOT.'core/HttpRequest.php';
		if (!$this->isTask) {
			require_once FR_ROOT.'core/HttpResponse.php';
		}
		require_once FR_ROOT.'core/FilterExecutor.php';

		$this->request = new HttpRequest($this);
		if (!$this->isTask) {
			$this->response = new HttpResponse($this);
		}
		$this->filterExecutor = new FilterExecutor($this);	
	}

	private function _getFilter($name,$defaults,$cover=false)
	{
		$filters = Conf::get($name, array());
		if (is_string($filters)) {
			$filters = array($filters);
		}
		if ($cover) {
			if ($filters) {
				return $filters;
			} else {
				return $defaults;
			}
		} else {
			$defaults = array_diff($defaults,$filters);
			return array_merge($defaults, $filters);
		}
	}

	private function _initFilter()
	{
		$filters['init'] = $this->_getFilter('hapn.filter.init',array('InputParseFilter'));
		$filters['input'] = $this->_getFilter('hapn.filter.input',array());
		$filters['url'] = $this->_getFilter('hapn.filter.url',array('URLDispatchFilter'),true);
		if (!$this->isTask) {
			$filters['output'] = $this->_getFilter('hapn.filter.output',array('OutputProcessFilter'));
		}
		$filters['clean'] = $this->_getFilter('hapn.filter.clean',array());

		$this->filterExecutor->loadFilters($filters);
	}

	function _goErrorPage($errcode)
	{
		$conf = Conf::get('hapn.error.redirect',array());
		$host = $this->request->host;
		if (!empty($conf[$host])) {
			$conf = $conf[$host];
		}
		$url = '/';
		if (isset($conf[$errcode])) {
			$url = $conf[$errcode];
		} elseif (isset($conf['hapn.error'])) {
			$url = $conf['hapn.error'];
		}
		$domain = $this->request->host;
		if (strncmp($domain,'http',4) !== 0) {
			$domain = 'http://'.$domain;
		}
		$url = str_replace('[url]',urlencode($domain.$this->request->uri),$url);
		$isUserEx = false;
		if (!$this->isUserErr($errcode)) {
			$di = base64_encode('ip='.$this->request->userip.':time='.$this->request->now.':id='.$this->appId); 
			if (strpos($url,'?') !== false) {
				$url .= '&di='.$di;
			} else {
				$url .= '?di='.$di;
			}
		} else {
			$isUserEx = true;
		}
		if ($errcode === 'hapn.u_notfound') {
			$this->response->setHeader('HTTP/1.0 404 Not Found');
		} elseif (!$isUserEx)  {
			$this->response->setHeader('HTTP/1.0 500 Internal Server Error');
		}
		if (true === $this->debug) {
			$this->response->sendHeaders();
			echo "<br/>Redirect: <a href='$url'>$url</a><br/>";
		} else {
			// 如果设置的文件是一个实际的路径，则直接输出内容，不跳转
			if (is_file($url)) {
				ob_clean();
				$output = include($url);
				$this->response->sendHeaders();
				$this->response->setRaw($output);
				exit;
			}
			$this->response->setHeader('Location: '.$url);
			//设置正常结束状态
			$this->response->sendHeaders();
			exit;
		}
	}

	function errorHandler()
	{
		$error = func_get_args();
		if (false === parent::errorHandler($error[0],$error[1],$error[2],$error[3]) || $this->isTask) { 
			return;
		}
		if (true === $this->debug) {
			unset($error[4]);
			echo "<pre>";
			print_r($error);
			echo "</pre>";
		}
		$errcode = 'hapn.fatal';
		$this->endStatus = $errcode;
		$this->response->setHapNHeader($errcode);
		if ($this->request->needErrorPage()) {
			$this->_goErrorPage($errcode);
		} else {
			$this->response->setError($error);
			$this->response->send();
		}
		exit;
	}

	function exceptionHandler($ex)
	{
		parent::exceptionHandler($ex);
		if ($this->isTask) {
			exit;
		}
		$errcode = $ex->getMessage();
		if (($pos = strpos($errcode,' ')) > 0) {
			$errcode = substr($errcode,0,$pos); 
		}
		$this->endStatus = $errcode;
		if (true === $this->debug) {
			echo "<pre>";
			print_r($ex->__toString());
			echo "</pre>";
		}
		if ($this->request->method == 'GET') { 
			$retrycode = Conf::get('hapn.error.retrycode','/\.net_/');
			$retrynum = $this->request->get('_retry',0);
			$retrymax = Conf::get('hapn.error.retrymax',1);
			if ($retrycode && $retrynum < $retrymax && 
				preg_match($retrycode,$errcode) > 0) {
					$retrynum++;
					$gets = array_merge($_GET, array('_retry'=>$retrynum));
					$url = $this->request->url .'?'.http_build_query($gets);
					$this->response->setHeader('X-Rewrite-URI: '.$url);
					$this->response->send();
					exit;
				}
		}
		$this->response->setHapNHeader($errcode);
		if ($this->request->needErrorPage()) {
			$this->_goErrorPage($errcode);
			exit;
		}
		$this->response->setException($ex);
		$this->response->send();
		exit;
	}

	function shutdownHandler()
	{
		$this->filterExecutor->executeFilter('clean');
		global $__HapN_appid;
		
		$r = $this->request;
		$ip = ($r->userip===$r->clientip)?
				$r->userip:($r->userip.'-'.$r->clientip);
				
		$basic = array('ip'=>$ip,'uri'=>$this->request->url,
			'logid'=>$this->appId.'-'.($__HapN_appid-$this->appId));
		
		if ($this->request->method != 'GET') {
			$basic['m'] = $this->request->method;
		}
		
		Logger::addBasic($basic);
		parent::shutdownHandler();
	}
}




/* vim: set ts=4 sw=4 sts=4 tw=100 noet: */
